package com.qi.fiveinrow;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 棋盘
 *
 * @author Administrator
 */
public class ChessBoard extends JPanel implements MouseListener, MouseMotionListener {

    private static final long serialVersionUID = -3032472182143269773L;
    private String state = Consts.PREPARING;
    Image chessBoardImage = null;
    List<Chess> chesses = null;
    /**
     * value 为每个点对应的权值
     */
    private final int boardLen = 15;
    int[][] value = new int[boardLen][boardLen];

    /**
     * 记录棋盘棋子:0没棋子  1	为白棋 2 为黑棋
     */
    int[][] record = new int[boardLen][boardLen];
    /**
     * x,y 为鼠标进入方形框
     */
    private int x = 0, y = 0;
    //谁先下棋
    String advancer = Consts.PLAYER;

    Player player = null;
    Player computer = null;
    double length = Consts.LENGTH; //单格长度
    private int n = 0;

    public ChessBoard() {
        value[7][7] = 1;
        //若电脑先下
        player = new Player(Consts.BLACK);
        computer = new Player(Consts.WHITE);
        chesses = new ArrayList<>();
        try {
//			chessboardimage = ImageIO.read(
//					new File("images/qipan2.png"));
            //用以下方法调用src中的图片
            //ClassLoader.getSystemResourceAsStream("images/qipan2.png")
            chessBoardImage = ImageIO.read(
                    (Objects.requireNonNull(ClassLoader.getSystemResourceAsStream("images/qipan2.png"))));

        } catch (Exception e) {
            e.printStackTrace();
        }
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public void paint(Graphics g) {

        g.drawImage(chessBoardImage, 0, 0,
                Consts.CHESSBOARD_WIDTH, Consts.CHESSBOARD_HEIGHT, null);

        this.drawFour(g);
        this.drawChesses(g);
    }

    public void mouseClicked(MouseEvent e) {
        // 游戏还没开始或者该位置已经有棋子了，直接返回
        if (!this.state.equals(Consts.RUNNING) || record[this.x][this.y] != 0){
            return;
        }
        //玩家下棋
        if (this.playerPutChess()) {
            //如果玩家胜利  playerPutChess()返回true
            JOptionPane.showMessageDialog(this, "You win!");
            this.state = Consts.PREPARING;
        }

        //电脑下棋
        if (this.computerPutChess()) {
            //如果电脑胜利  computerPutChess()返回true
            JOptionPane.showMessageDialog(this, "You fail!");
        }
    }

    public void newGame() {
        this.state = Consts.RUNNING;
        this.chesses.clear();
        player.chesses.clear();
        computer.chesses.clear();
        for (int i = 0; i < boardLen; i++) {
            for (int j = 0; j < boardLen; j++) {
                value[i][j] = 0;  // 初始化权值
                record[i][j] = 0; //初始化棋子
                if (i == boardLen/2 && j == boardLen/2) //先手位置
                    value[i][j] = 1;
            }
        }
        this.state = Consts.PREPARING;
        this.repaint();
    }

    public void startGame() {
        this.state = Consts.RUNNING;
        if (this.advancer.equals(Consts.COMPUTER)) {
            this.computerPutChess();
            this.repaint();
        }
    }

    //改变先手
    public String changeAdvancer() {
        if (this.state.equals(Consts.PREPARING)) {
            if (this.advancer.equals(Consts.PLAYER)) {
                this.advancer = Consts.COMPUTER;
                this.computer.color = Consts.BLACK;
                this.player.color = Consts.WHITE;
            } else if(this.advancer.equals(Consts.COMPUTER)){
                this.advancer = Consts.PLAYER;
                this.player.color = Consts.BLACK;
                this.computer.color = Consts.WHITE;
            }
        }
        return this.advancer;
    }

    // 悔棋
    public void huiqi() {
        int i = this.chesses.size();
        if (i == 0){
            return;
        }
        Chess chess = this.chesses.get(i - 1);
        int x0 = chess.getX();
        int y0 = chess.getY();
        record[x0][y0] = 0;

        this.chesses.remove(i - 1);

        chess = this.chesses.get(i - 2);
        int x1 = chess.getX();
        int y1 = chess.getY();
        record[x1][y1] = 0;

        this.chesses.remove(i - 2);

        this.changeCloseValue(x0, y0);
        this.changeCloseValue(x1, y1);

        if (this.chesses.size() != 0)
            this.state = Consts.RUNNING;
        this.repaint();
    }
    public boolean playerPutChess(Player player, Chess chess) {
        if (!this.state.equals(Consts.RUNNING)){
            return false;
        }
        this.chesses.add(chess);
        player.addChess(chess);
        boolean t = this.isWin(chess.x, chess.y, chess.color);
        this.record[chess.x][chess.y] = Integer.parseInt(player.color);//2代表（x,y）处为黑棋
        this.changeCloseValue(chess.x, chess.y);
        value[chess.x][chess.y] = -1;
        if (this.state.equals(Consts.RUNNING)) {
            this.repaint();
            if (t){
                this.state = Consts.PREPARING;
            }
        }
        return t;

    }

    public boolean playerPutChess() {
        Chess chess = new Chess(this.x, this.y, this.player.color);
        return playerPutChess(this.player, chess);
    }

    //电脑下棋
    public boolean computerPutChess() {
        if (!this.state.equals(Consts.RUNNING)){
            return false;
        }
        int max = 0;
        List<Integer> q = new ArrayList<>();
        //寻找权值最大的点
        for (int i = 0; i < boardLen; i++) {
            for (int j = 0; j < boardLen; j++) {
                if (max < value[i][j]) {
                    max = value[i][j];
                    q.clear();
                    q.add(i * 100 + j);
                } else if (max == value[i][j]) {
                    q.add(i * 100 + j);
                }
            }
        }

        //随机选取值最大的其中一个
        int random = (int) (Math.random() * q.size());
        random =  q.get(random);
        Chess chess = new Chess(random / 100, random % 100, computer.color);
        return playerPutChess(this.computer, chess);
    }


    public void drawFour(Graphics g) {
        if (this.record[this.x][this.y] == 0) {
            g.setColor(Color.red);
            //左上
            g.drawLine((int) (30 + length * this.x) - 15, (int) (30 + length * this.y) - 15,
                    (int) (30 + length * this.x) - 15, (int) (30 + length * y) - 4);
            g.drawLine((int) (30 + length * this.x) - 15, (int) (30 + length * this.y) - 15,
                    (int) (30 + length * this.x) - 4, (int) (30 + length * this.y) - 15);
            //左下
            g.drawLine((int) (30 + length * this.x) - 15, (int) (30 + length * this.y) + 8,
                    (int) (30 + length * this.x) - 15, (int) (30 + length * this.y) + 20);
            g.drawLine((int) (30 + length * this.x) - 15, (int) (30 + length * this.y) + 20,
                    (int) (30 + length * this.x) - 4, (int) (30 + length * this.y) + 20);
            //右上
            g.drawLine((int) (30 + length * this.x) + 15, (int) (30 + length * this.y) - 15,
                    (int) (30 + length * this.x) + 15, (int) (30 + length * this.y) - 4);
            g.drawLine((int) (30 + length * this.x) + 15, (int) (30 + length * this.y) - 15,
                    (int) (30 + length * this.x) + 4, (int) (30 + length * this.y) - 15);
            //右下
            g.drawLine((int) (30 + length * this.x) + 15, (int) (30 + length * this.y) + 20,
                    (int) (30 + length * this.x) + 15, (int) (30 + length * this.y) + 8);
            g.drawLine((int) (30 + length * this.x) + 15, (int) (30 + length * this.y) + 20,
                    (int) (30 + length * this.x) + 4, (int) (30 + length * this.y) + 20);

            g.setColor(Color.black);
        }
    }

    public void drawChesses(Graphics g) {
        for (int i = 0; i < this.chesses.size(); i++) {
            Chess chess = this.chesses.get(i);
            g.drawImage(chess.image, chess.getX0() - 15,
                    chess.getY0() - 15, 30, 30, null);
            if (i == this.chesses.size() - 1) {
                g.setColor(Color.red);
                g.fillOval(chess.getX0() - 8, chess.getY0() - 8, 16, 16);
                g.setColor(Color.white);
                g.fillOval(chess.getX0() - 4, chess.getY0() - 4, 8, 8);
                g.setColor(Color.black);
            }
        }
    }

    public void mousePressed(MouseEvent e) {


    }

    public void mouseReleased(MouseEvent e) {

    }

    public void mouseEntered(MouseEvent e) {

    }

    public void mouseExited(MouseEvent e) {

    }

    public void mouseDragged(MouseEvent e) {

    }

    /**
     * 鼠标位置转换为棋盘坐标
     */
    public void mouseMoved(MouseEvent e) {

        double x0 = (e.getX() - 30) / length;
        if (x0 > (int) x0 + 0.5) {
            x = (int) x0 + 1;
        } else {
            x = (int) x0;
        }
        double y0 = (e.getY() - 30) / length;
        if (y0 > (int) y0 + 0.5) {
            y = (int) y0 + 1;
        } else {
            y = (int) y0;
        }

        if (y > 14) y = 14;
        if (x > 14) x = 14;
        this.repaint();
    }

    // 改变棋子附近的权值
    public void changeCloseValue(int x, int y) {
        int x0 = x - 4, y0 = y;
        while (true) {
            if (x0 >= 0) {
                if (record[x0][y0] == 0) {
                    value[x0][y0] = this.getValue(x0, y0);
                }
            }
            x0++;
            if (x0 > x + 4 || x0 > 14) {
                break;
            }
        }
        x0 = x;
        y0 = y - 4;
        while (true) {
            if (y0 >= 0) {
                if (record[x0][y0] == 0) {
                    value[x0][y0] = this.getValue(x0, y0);
                }
            }
            y0++;
            if (y0 > y + 4 || y0 > 14) {
                break;
            }
        }
        x0 = x - 4;
        y0 = y - 4;
        while (true) {
            if (x0 >= 0 && y0 >= 0 && x0 <= 14 && y0 <= 14) {
                if (record[x0][y0] == 0) {
                    value[x0][y0] = this.getValue(x0, y0);
                }
            }
            x0++;
            y0++;
            if (y0 > y + 4 || y0 > 14 || x0 > x + 4 || x > 14) {
                break;
            }
        }
        x0 = x - 4;
        y0 = y + 4;
        while (true) {
            if (x0 >= 0 && y0 >= 0 && x0 <= 14 && y0 <= 14) {
                if (record[x0][y0] == 0) {
                    value[x0][y0] = this.getValue(x0, y0);
                }
            }
            x0++;
            y0--;
            if (y0 < y - 4 || y0 < 0 || x0 > x + 4 || x > 14) {
                break;
            }
        }
    }

    public boolean isWin(int x, int y, String color) {
        boolean flag = false;
        int a1[] = this.sunLineRow(x, y, color);
        if (a1[0] == 5)
            flag = true;
        else {
            int b1[] = this.sunLineColumn(x, y, color);
            if (b1[0] == 5)
                flag = true;
            else {
                int c1[] = this.moonLineLeftUp(x, y, color);
                if (c1[0] == 5)
                    flag = true;
                else {
                    int d1[] = this.moonLineLeftDown(x, y, color);
                    if (d1[0] == 5)
                        flag = true;
                }
            }
        }

        return flag;
    }

    /**
     * 权值算法
     *
     * @param x
     * @param y
     * @return
     */
    public int getValue(int x, int y) {
        int num = 0;
        int a1[] = this.sunLineRow(x, y, computer.color);
        int b1[] = this.sunLineColumn(x, y, computer.color);
        int c1[] = this.moonLineLeftUp(x, y, computer.color);
        int d1[] = this.moonLineLeftDown(x, y, computer.color);
        List<int[]> m = new ArrayList<>();
        m.add(a1);
        m.add(b1);
        m.add(c1);
        m.add(d1);
        this.n = 0;
        for (int i = 0; i < m.size(); i++) {
            int t[] = m.get(i);
            num = num + this.isFive(t, computer.color)
                    + this.isFour(t, computer.color)
                    + this.isThree(t, computer.color)
                    + this.isTwo(t, computer.color);
        }
        if (n >= 2) {
            num += 50000;
        }
        int a2[] = this.sunLineRow(x, y, player.color);
        int b2[] = this.sunLineColumn(x, y, player.color);
        int c2[] = this.moonLineLeftUp(x, y, player.color);
        int d2[] = this.moonLineLeftDown(x, y, player.color);
        m.clear();
        m.add(a2);
        m.add(b2);
        m.add(c2);
        m.add(d2);
        this.n = 0;
        for (int i = 0; i < m.size(); i++) {
            int t[] = m.get(i);
            num = num + this.isFive(t, computer.color)
                    + this.isFour(t, computer.color)
                    + this.isThree(t, computer.color)
                    + this.isTwo(t, computer.color);
        }
        if (n >= 2) {
            num += 40000;
        }
        return num;
    }

    /**
     * a[0] 代表相同颜色棋子数
     * a[1] 上边，左边 ，左上，左下空格数
     * a[2] 下边右边，右上，右下空格数
     *
     * @param x
     * @param y
     * @param color1 棋子颜色
     * @return 返回a[]的数组
     */
    public int[] sunLineRow(int x, int y, String color1) {

        //a[0] = 0;  //代表相同颜色棋子数
        //a[1] = 0;//上边，左边 ，左上，左下空格数
        //a[2] = 0; //下边右边，右上，右下空格数
        int a[] = new int[3];

        int color = Integer.parseInt(color1);
        record[x][y] = color;
        int x0 = x - 4, y0 = y;
        boolean flag = false;
        while (true) {
            if (x0 >= 0 && x0 <= 14) {
                if (record[x0][y0] == color) {
                    a[0]++;
                } else {
                    if (x0 < x) {
                        a[0] = 0;
                    } else if (x0 > x) {
                        //此时（x0,y0）已经是最左边与color相同的棋子
                        //判断左右空格
                        /*左边*/
                        for (int i = x0 - a[0] - 1; i >= 0; i--) {
                            if (record[i][y0] == 0) {
                                a[1]++;
                            } else {
                                break;
                            }
                        }
                        /*右边*/
                        for (int i = x0; i <= 14; i++) {
                            if (record[i][y0] == 0) {
                                a[2]++;
                            } else {
                                break;
                            }
                        }
                        flag = true;
                    }
                }
            }
            x0++;
            if (x0 > 14 || x0 > x + 4 || flag) {
                break;
            }
        }

        record[x][y] = 0;

        return a;
    }

    public int[] sunLineColumn(int x, int y, String color1) {
        int a[] = new int[3];
        a[0] = 0;  //代表相同颜色棋子数
        a[1] = 0;//上边，左边 ，左上，左下空格数
        a[2] = 0; //下边右边，右上，右下空格数
        int color = Integer.parseInt(color1);
        record[x][y] = color;
        int x0 = x, y0 = y - 4;
        boolean flag = false;
        while (true) {
            if (y0 >= 0 && y0 <= 14) {
                if (record[x0][y0] == color) {
                    a[0]++;
                } else {
                    if (y0 < y) {
                        a[0] = 0;
                    } else if (y0 > y) {
                        //此时（x0,y0）已经是最左边与color相同的棋子
                        //判断左右空格
                        /*左边*/
                        for (int i = y0 - a[0] - 1; i >= 0; i--) {
                            if (record[x0][i] == 0) {
                                a[1]++;
                            } else {
                                break;
                            }
                        }
                        /*右边*/
                        for (int i = y0; i <= 14; i++) {
                            if (record[x0][i] == 0) {
                                a[2]++;
                            } else {
                                break;
                            }
                        }
                        flag = true;
                    }
                }
            }
            y0++;
            if (y0 > 14 || y0 > y + 4 || flag) {
                break;
            }
        }
        record[x][y] = 0;
        return a;
    }

    public int[] moonLineLeftUp(int x, int y, String color1) {
        int a[] = new int[3];
        a[0] = 0;  //代表相同颜色棋子数
        a[1] = 0;//上边，左边 ，左上，左下空格数
        a[2] = 0; //下边右边，右上，右下空格数
        int color = Integer.parseInt(color1);
        record[x][y] = color;
        int x0 = x - 4, y0 = y - 4;
        boolean flag = false;
        while (true) {
            if (y0 >= 0 && y0 <= 14 && x0 >= 0 && x0 <= 14) {
                if (record[x0][y0] == color) {
                    a[0]++;
                } else {
                    if (y0 < y && x0 < x) {
                        a[0] = 0;
                    } else if (y0 > y && x0 > x) {
                        //此时（x0,y0）已经是最左边与color相同的棋子
                        //判断左右空格
                        /*左边*/
                        int i, j;
                        for (i = x0 - a[0] - 1, j = y0 - a[0] - 1; i >= 0 && j >= 0; i--, j--) {
                            if (record[i][j] == 0) {
                                a[1]++;
                            } else {
                                break;
                            }
                        }
                        /*右边*/
                        for (i = x0, j = y0; i <= 14 && j <= 14; i++, j++) {
                            if (record[i][j] == 0) {
                                a[2]++;
                            } else {
                                break;
                            }
                        }
                        flag = true;
                    }
                }
            }
            x0++;
            y0++;
            if (y0 > 14 || y0 > y + 4 || flag || x0 > 14 || x0 > x + 4) {
                break;
            }
        }
        record[x][y] = 0;
        return a;
    }

    public int[] moonLineLeftDown(int x, int y, String color1) {
        int a[] = new int[3];
        a[0] = 0;  //代表相同颜色棋子数
        a[1] = 0;//上边，左边 ，左上，左下空格数
        a[2] = 0; //下边右边，右上，右下空格数
        int color = Integer.parseInt(color1);
        record[x][y] = color;
        int x0 = x - 4, y0 = y + 4;
        boolean flag = false;
        while (true) {
            if (y0 >= 0 && y0 <= 14 && x0 >= 0 && x0 <= 14) {
                if (record[x0][y0] == color) {
                    a[0]++;
                } else {
                    if (y0 > y && x0 < x) {
                        a[0] = 0;
                    } else if (y0 < y && x0 > x) {
                        //此时（x0,y0）已经是最左边与color相同的棋子
                        //判断左右空格
                        /*左边*/
                        int i, j;
                        for (i = x0 - a[0] - 1, j = y0 + a[0] + 1; i >= 0 && j <= 14; i--, j++) {
                            if (record[i][j] == 0) {
                                a[1]++;
                            } else {
                                break;
                            }
                        }
                        /*右边*/
                        for (i = x0, j = y0; i <= 14 && j >= 0; i++, j--) {
                            if (record[i][j] == 0) {
                                a[2]++;
                            } else {
                                break;
                            }
                        }
                        flag = true;
                    }
                }
            }
            x0++;
            y0--;
            if (y0 < 0 || y0 < y - 4 || flag || x0 > 14 || x0 > x + 4) {
                break;
            }
        }
        record[x][y] = 0;
        return a;
    }

    public int isFive(int a[], String color) {
        int value = 0;
        if (a[0] >= 5) {
            if (color.equals(computer.color))
                value = 1000000;
            else if (color.equals(player.color))
                value = 500000;
        }
        return value;
    }

    public int isFour(int a[], String color) {
        int value = 0;
        if (a[0] == 4) {
            //活4
            if (a[1] > 0 && a[2] > 0) {
                if (color.equals(computer.color))
                    value = 200000;
                else if (color.equals(player.color))
                    value = 130000;
            }
            //冲4
            else if ((a[1] > 0 && a[2] == 0) || (a[1] == 0 && a[2] > 0)) {
                value = 14000;
                n++;
            }
            //死4
            else if (a[1] == 0 && a[2] == 0) {
                value = 0;
            }
        }
        return value;
    }

    public int isThree(int a[], String color) {
        int value = 0;
        if (a[0] == 3) {
            //活3
            if (a[1] > 0 && a[2] > 0 && (a[1] + a[2] >= 3)) {
                if (color.equals(computer.color))
                    value = 14000;
                else if (color.equals(player.color))
                    value = 10000;
                n++;
            }
            //眠3
            else if ((a[1] == 0 && a[2] >= 2) || (a[1] >= 2 && a[2] == 0)) {
                value = 3000;
            } else
                value = 0;
        }
        return value;
    }

    public int isTwo(int a[], String color) {
        int value = 0;
        if (a[0] == 2) {
            //活2
            if (a[1] > 0 && a[2] > 0 && (a[1] + a[2] >= 4)) {
                value = 1000;
            }
            //眠2
            else if ((a[1] == 0 && a[2] >= 3) && a[2] == 0 && a[1] >= 3) {
                value = 500;
            }
            //死2
            else if (a[1] + a[2] <= 2) {
                value = 0;
            }
        }
        return value;
    }
}


